home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume17 / e2 / part03 < prev    next >
Encoding:
Internet Message Format  |  1989-02-08  |  29.1 KB

  1. Subject:  v17i097:  E, friendlier front-end to vi, Part03/03
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: speedboat jones <tcjones@watdragon.waterloo.edu>
  7. Posting-number: Volume 17, Issue 97
  8. Archive-name: e2/part03
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 3 (of 3)."
  17. # Contents:  do_vi.c e.1 e.c read_hist.c
  18. # Wrapped by tcjones@watdragon on Thu Feb  9 10:01:03 1989
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. if test -f 'do_vi.c' -a "${1}" != "-c" ; then 
  21.   echo shar: Will not clobber existing file \"'do_vi.c'\"
  22. else
  23. echo shar: Extracting \"'do_vi.c'\" \(4970 characters\)
  24. sed "s/^X//" >'do_vi.c' <<'END_OF_FILE'
  25. X#include "e.h"
  26. X
  27. X/* 
  28. X * do_vi()
  29. X *
  30. X * Split the arguments (if any) in 'thing' up to be passed to execvp,
  31. X * and exec vi on them. The arguments in 'thing' are space separated.
  32. X * Just walk down the 'thing' array, zero the spaces and set pointers 
  33. X * to the arguments.
  34. X *
  35. X */
  36. X
  37. void
  38. do_vi(thing)
  39. char *thing;
  40. X{
  41. X    char *args[MAX_ARGS];
  42. X    register int i = 1;
  43. X    int go_home = 0;
  44. X
  45. X    args[0] = "vi";
  46. X    skip_white(thing);
  47. X
  48. X    while (*thing){
  49. X        register char *tmp = thing;
  50. X        skip_to_white(tmp);
  51. X        if (*tmp) *tmp++ = '\0';
  52. X        skip_white(tmp);
  53. X
  54. X        if (i > 1 || (*thing != '-' && *thing != '+')){
  55. X            if (safety_first(thing)){
  56. X                /*
  57. X                 * Have to go home for this one.
  58. X                 * Grab some space to put the new filename into.
  59. X                 * The filename is to be cwd/thing.
  60. X                 *
  61. X                 */
  62. X                char *space = sbrk(MAXPATHLEN + 1);
  63. X                go_home = 1;
  64. X                if (space == (char *)-1){
  65. X                    e_error("Could not sbrk.");
  66. X                }
  67. X                sprintf(space, "%s/%s", cwd, thing);
  68. X                thing = space;
  69. X            }
  70. X        }
  71. X        args[i++] = thing;
  72. X        thing = tmp;
  73. X    }
  74. X
  75. X    args[i] = NULL;
  76. X
  77. X    if (go_home && chdir(home) == -1){
  78. X        e_error("Could not chdir to '%s'.", home);
  79. X    }
  80. X        
  81. X    if (execvp(VI, args) == -1){
  82. X        e_error("Could not execvp '%s'", VI);
  83. X    }
  84. X}
  85. X
  86. X
  87. int
  88. safety_first(s)
  89. char *s;
  90. X{
  91. X    register char *slash;
  92. X    struct stat sbuf;
  93. X    char away_dir[MAXPATHLEN];
  94. X    int away;
  95. X    int own;
  96. X
  97. X    /*
  98. X     * If they are not concerned with inheritance, just return.
  99. X     *
  100. X     */
  101. X    if (!safe_inherit && !inherit){
  102. X        return 0;
  103. X    }
  104. X
  105. X    /*
  106. X     * See if there is a .exrc file in the directory in which the file we
  107. X     * are going to be editing lives.
  108. X     */
  109. X    slash = rindex(s, '/');
  110. X
  111. X    if (slash){
  112. X        /*
  113. X         * The file we are editing lies (probably) in a directory that is 
  114. X         * not the one we are in. Check it by inode numbers though.
  115. X         *
  116. X         */
  117. X        char tmp[MAXPATHLEN];
  118. X        ino_t here_ino;
  119. X
  120. X        *slash = '\0';
  121. X        ok_sprintf(away_dir, "%s", s);
  122. X        *slash = '/';
  123. X        ok_sprintf(tmp, "%s/.exrc", away_dir);
  124. X
  125. X        if (stat(tmp, &sbuf) == -1){
  126. X            /*
  127. X             * There is no .exrc file.
  128. X             *
  129. X             */
  130. X            return 0;
  131. X        }
  132. X        
  133. X        /*
  134. X         * There is a .exrc file.
  135. X         *
  136. X         */
  137. X        if (uid == sbuf.st_uid){
  138. X            /*
  139. X             * And we own it.
  140. X             *
  141. X             */
  142. X            away = 1;
  143. X            own = 1;
  144. X        }
  145. X        else{
  146. X            /*
  147. X             * We don't own the .exrc file. 
  148. X             *
  149. X             */
  150. X            own = 0;
  151. X        }
  152. X
  153. X        /*
  154. X         * Decide whether or not the file we are going to edit is in
  155. X         * this directory. We may have been deceived by the presence of the
  156. X         * '/' since the filename could be ../this_dir etc etc.
  157. X         *
  158. X         */
  159. X
  160. X        if (stat(cwd, &sbuf) == -1){
  161. X            e_error("Cannot stat '%s'.", cwd);
  162. X        }
  163. X        here_ino = sbuf.st_ino;
  164. X
  165. X        if (stat(away_dir, &sbuf) == -1){
  166. X            e_error("Cannot stat '%s'.", away_dir);
  167. X        }
  168. X
  169. X        if (sbuf.st_ino == here_ino){
  170. X             away = 0;
  171. X        }
  172. X        else{
  173. X            away = 1;
  174. X        }
  175. X    }
  176. X    else{
  177. X        /*
  178. X         * The file is in this directory.
  179. X         *
  180. X         */
  181. X
  182. X        /*
  183. X         * We know we are away, there was no '/' in the filename.
  184. X         * The possibility of the filename being a link is excluded I
  185. X         * think, because earlier on we checked for regular files.
  186. X         * I'll check this again. In any case no harm could come as
  187. X         * at worst we would attempt to vi a directory.
  188. X         *
  189. X         */
  190. X        away = 0;
  191. X
  192. X        if (stat(".exrc", &sbuf) == -1){
  193. X            /*
  194. X             * No .exrc file.
  195. X             *
  196. X             */
  197. X            return 0;
  198. X        }
  199. X
  200. X        if (uid == sbuf.st_uid){
  201. X            own = 1;
  202. X        }
  203. X        else{
  204. X            own = 0;
  205. X        }
  206. X    }
  207. X
  208. X    /*
  209. X     * We have now set up 'away' and 'own'.
  210. X     *
  211. X     * away = 1  =>  The file we are editing is not in our current directory.
  212. X     * away = 0  =>  The file we are editing is in our current directory.
  213. X     *
  214. X     * own = 1   =>  We own the .exrc file.
  215. X     * own = 0   =>  We do not own the .exrc file.
  216. X     *
  217. X     *
  218. X     */
  219. X
  220. X    /*
  221. X     * It's in this directory and we own it. So just return and pretend
  222. X     * to be a normal vi :-)
  223. X     *
  224. X     */
  225. X    if (!away && own){
  226. X        return 0;
  227. X    }
  228. X
  229. X    /*
  230. X     * It's in this directory and we don't own it and we don't want to inherit
  231. X     * it. 
  232. X     *
  233. X     * Return 1 to indicate that the filename that needs to be edited 
  234. X     * should now be preceeded by 'cwd/'. And that we need to chdir to home
  235. X     * before we exec vi.
  236. X     *
  237. X     */
  238. X    if (!away && !own && safe_inherit){
  239. X        return 1;
  240. X    }
  241. X
  242. X    /*
  243. X     * The other option is that it's in this directory and we don't own
  244. X     * it and either 1) inherit is set or 2) inherit is not set AND neither
  245. X     * is safe_inherit. In either case we are going to inherit the thing.
  246. X     *
  247. X     */
  248. X
  249. X     /*
  250. X      * Now to the cases where the file we are going to edit is not in
  251. X      * this directory.
  252. X      *
  253. X      */
  254. X
  255. X    /*
  256. X     * It's not in this directory and we own it and we want to inherit. 
  257. X     * So chdir over there before returning.
  258. X     *
  259. X     */
  260. X    if (away && own && inherit){
  261. X        if (chdir(away_dir) == -1){
  262. X            e_error("Could not chdir to '%s'.", away_dir);
  263. X        }
  264. X        return 0;
  265. X    }
  266. X
  267. X    /*
  268. X     * It's not in this directory and we don't own it and we want to inherit
  269. X     * even if it's not safe. So chdir over there before returning.
  270. X     *
  271. X     */
  272. X    if (away && !own && inherit && !safe_inherit){
  273. X        if (chdir(away_dir) == -1){
  274. X            e_error("Could not chdir to '%s'.", away_dir);
  275. X        }
  276. X        return 0;
  277. X    }
  278. X
  279. X    /*
  280. X     * And I think that's about it. Time will tell.
  281. X     *
  282. X     */
  283. X    
  284. X    return 0;
  285. X}
  286. END_OF_FILE
  287. if test 4970 -ne `wc -c <'do_vi.c'`; then
  288.     echo shar: \"'do_vi.c'\" unpacked with wrong size!
  289. fi
  290. # end of 'do_vi.c'
  291. fi
  292. if test -f 'e.1' -a "${1}" != "-c" ; then 
  293.   echo shar: Will not clobber existing file \"'e.1'\"
  294. else
  295. echo shar: Extracting \"'e.1'\" \(9576 characters\)
  296. sed "s/^X//" >'e.1' <<'END_OF_FILE'
  297. X.TH E P "November 16, 1988"
  298. X.SH NAME
  299. e \- command line preprocessor for the vi(1) editor. 
  300. X.SH SYNOPSIS
  301. X.B e
  302. X[
  303. X.B option
  304. X] [
  305. X.B file
  306. X] ...
  307. X.SH DESCRIPTION
  308. X.I e 
  309. is an interface to 
  310. X.IR vi (1)
  311. that maintains a history of the most recently 
  312. X.IR e 'ed
  313. files for each directory. 
  314. Using the history, it is both fast and simple to re-edit
  315. previously 
  316. X.IR e 'ed
  317. files.
  318. X.PP
  319. In addition, 
  320. X.I e
  321. does spelling corrections on its arguments,
  322. fast lookup and editing of files in other directories, and allows for
  323. the inheritance of .exrc
  324. files in other directories. It also closes the modeline security hole,
  325. making it possible to ensure that no .exrc file 
  326. that you don't own is ever seen by 
  327. X.IR vi .
  328. X.PP
  329. X.SH INVOCATION
  330. The invocation syntax is (almost) a superset of that of 
  331. X.IR vi .
  332. A list of the interesting command line variations is given below.
  333. X[x] indicates that "x" is optional. "cmd" means an
  334. X.IR ex (1)
  335. command.
  336. X.TP 18
  337. X.B e           
  338. Invokes 
  339. X.I vi 
  340. on the last file that was 
  341. X.IR e 'ed
  342. in this directory.
  343. X.TP 18
  344. X.B e \-
  345. Prints the history for this directory and allows fast selection
  346. of a previous file - or a new one.
  347. X.TP 18
  348. X.B e .
  349. Prints the history for this directory without asking for input.
  350. X.TP 18
  351. X.B e \-pat
  352. X.IR vi 's 
  353. the last file that was 
  354. X.IR e 'ed
  355. with the string "pat" on
  356. the command line.
  357. X.TP 18
  358. X.B e +[cmd]
  359. X.IR vi 's 
  360. the last file that was 
  361. X.IR e 'ed
  362. in this directory, but executes
  363. command "cmd" on entering
  364. X.IR vi .
  365. X.TP 18
  366. X.B e [+[cmd]] file  
  367. X.IR vi 's 
  368. the file and adds it to the history list. Minor spelling
  369. corrections are suggested if "file" does not exist but is close 
  370. X(in spelling) to some file that does.
  371. X.TP 18
  372. X.B e [+[cmd]] files 
  373. X.IR vi 's 
  374. the files and adds them as a single entry to the history.
  375. X.PP
  376. The 
  377. X.IR vi (1)
  378. options \-r, \-v, \-x, \-w and \-R are all passed as is to 
  379. X.I vi
  380. and so behave as would be expected.
  381. X.SH EXAMPLE
  382. Assume here that you are in the directory /tmp/mydir and that it
  383. contains (only) the files "death", "main.c", "pete.c", "bigmac"
  384. and "fries"; and that your 
  385. X.I e 
  386. history file contains
  387. X.PP
  388. X.in 0.5i
  389. X.B /tmp/mydir
  390. X.in 1.0i
  391. X.B death
  392. X.br
  393. X.B +/main.c pete.c
  394. X.br
  395. X.B bigmac
  396. X.br
  397. X.B fries
  398. X.br
  399. X.PP
  400. X"\fBe .\fR" will show you the history...
  401. X.PP
  402. X.in 1.0i
  403. X.B [3]: death
  404. X.br
  405. X.B [2]: +/main pete.c
  406. X.br
  407. X.B [1]: bigmac
  408. X.br
  409. X.B [0]: fries
  410. X.br
  411. X.PP
  412. X"\fBe\fR" by itself will get you immediately back into "fries".
  413. X.PP
  414. X"\fBe \-\fR" will present the same as shown for "\fBe .\fR",
  415. but will ask for a number or another filename.
  416. Carriage return is equivalent to zero (i.e. the last filename),
  417. backspace or interrupt will quit.
  418. X.PP
  419. X"\fBe -2\fR" will get you immediately into "pete.c", searching for
  420. X"main" on entering 
  421. X.IR vi .
  422. X.PP
  423. X"\fBe \-ath\fR" searches for the pattern "ath", finds it in "death",
  424. and that's what you get.
  425. X.PP
  426. X"\fBe +10\fR"
  427. will get you into "fries" on line 10 (assuming it has 10 lines).
  428. X.SH "THE HISTORY"
  429. A single history file is kept. Its default location is $HOME/.e but this
  430. can be changed with the VIHIST environment variable.
  431. The history is rearranged with each use to place the last
  432. X.IR e 'ed
  433. file at the end of the list. Duplicate entries are removed.
  434. The number of history items kept for each directory is 8. Seeing as the
  435. list is ordered by use, this number is ample.
  436. X.PP
  437. The history file consists of entries composed of a directory name followed by
  438. lines of file names (oldest to newest). Each filename is preceded by a 
  439. single TAB character. The directory names are all absolute pathnames.
  440. X.SH "FILENAME CORRECTION"
  441. If you make a simple spelling mistake when typing a file name,
  442. X.I e
  443. will detect it, ask whether it was really what you meant, and offer
  444. suggestions.
  445. XErrors that are detected are: wrong character, omitted character, 
  446. interchanged characters and extra character.
  447. X.PP
  448. In the above example,
  449. X"\fBe bigamc\fR"
  450. will prompt you with 
  451. X.br
  452. X.in 1.0i
  453. X"correct to bigmac [y]?"
  454. X.PP
  455. Answering "n" will not do the correction, "Q" or "q" will quit.
  456. If there is more than one possible correction, 
  457. you will be prompted for each in
  458. turn. A response of "N" means that you really want what you typed, and no
  459. further corrections will be offered.
  460. Any other response (e.g. a RETURN) will do the correction for you.
  461. X.SH "CROSS-DIRECTORY EDITING"
  462. The environment variable VIPATH can be used to enable fast lookup and 
  463. editing of files
  464. in different directories. It should contain a list of directories that you want
  465. searched when 
  466. X.I e
  467. cannot find the file you request in the current
  468. directory. Here is an example:
  469. X.PP
  470. Suppose you are in the directory /bin with VIPATH set to /usr/include/sys
  471. X.PP
  472. X"\fBe inode.h\fR"
  473. will prompt you with 
  474. X.br
  475. X.in 1.0i
  476. X"/usr/include/sys/inode.h [y]?"
  477. X.PP
  478. since /bin/inode.h does not exist, but /usr/include/sys/inode.h does.
  479. You can say "n" or "q" to reject or quit. 
  480. X"N" will reject the current suggestion and
  481. searching for further ones will be stopped.
  482. Any other response (e.g. a RETURN) is taken as a yes.
  483. X.PP
  484. It is handy to have $HOME in your VIPATH, this gives you easy access
  485. from anywhere to commonly used files.
  486. X.PP
  487. If you accept a suggestion, then the file is put into the history. 
  488. Spelling corrections are not suggested across directories.
  489. There is (of course) no need to put "." in your VIPATH. Doing so will just slow
  490. things down and cannot possibly be of help.
  491. This should be clear, "." is always searched first for the given filename.
  492. Putting it into your VIPATH will have it searched twice. The directory names
  493. in VIPATH may be separated by white space (including newlines) and colons.
  494. X.SH ".exrc INHERITANCE"
  495. If you set the environment variable "VIINHERIT", 
  496. X.I e
  497. will look for 
  498. a .exrc file in the directory where the (first) file you are about to edit 
  499. resides. If it finds
  500. one, it arranges to read it as though it were in the directory from which you
  501. issued the 
  502. X.I e
  503. command. This is very useful as many people 
  504. have specialised .exrc files in their directory trees. 
  505. X.PP
  506. XFor instance, in a directory of C source
  507. you might like to set autoindent and showmatch, whereas in a directory that
  508. contained correspondence, you might want neither of these, but wrapmargin and
  509. ignorecase instead. Inherited .exrc files allow you to 
  510. X.I e
  511. files in other
  512. directories and get the results intended by the .exrc files in them.
  513. X.PP
  514. There is a drawback however. 
  515. X.I vi
  516. has an option called "modeline"
  517. which makes it possible for a malicious user to leave a trojan-horse type file
  518. in a directory with a specially prepared .exrc file that turns on "modeline".
  519. As a result, if you cd to that directory and 
  520. X.I vi
  521. the wrong file, then the modeline feature allows the other user to execute
  522. commands as you. Not nice.
  523. X.PP
  524. If you set "VISAFEINHERIT", 
  525. X.I e
  526. will make sure that you never get caught by
  527. this one. In short, it notices when this could happen and changes directory
  528. to avoid the .exrc. There is no need to have "VIINHERIT" set if all you want to
  529. do is avoid the security problem. But setting them both gives you the best of
  530. both worlds. (See the NOTES for the drawback...)
  531. X.SH NOTES
  532. When using "e -", the terminal is put into cbreak mode. If the first
  533. character typed is a digit (in the acceptable range of history items)
  534. then you will get that history item without further ado. Thus if you
  535. have a file called 4play and you try to type "4play" from within an "e -", 
  536. then you'll probably end up in the wrong place.
  537. This is to say you'll get the file that was the 4th last in the history.
  538. X.PP
  539. The history length must be less than or equal to 9 (the code sets
  540. it to 8 at present). 
  541. The problem with having more is that with "e -" you go into cbreak and the 
  542. first digit entered (say 
  543. X.I n
  544. X) is taken to mean 
  545. X"I want the 
  546. X.IR n th 
  547. last file". This saves the need for hitting return, but also means that
  548. two digit numbers can't be done.
  549. X.PP
  550. When "VISAFEINHERIT" is set and your command would have resulted in 
  551. X.I vi
  552. going through a foreign .exrc, 
  553. X.I e
  554. will change the name
  555. of the file you want to its full path name, and change directory underneath
  556. you to your home directory. For example, if user joe says "e file" in /tmp and
  557. user mary owns /tmp/.exrc, then the result will be as though joe had typed "e
  558. X/tmp/file" from his home directory. Of course when he exits 
  559. X.I vi 
  560. he will still 
  561. be in /tmp. Perhaps this could be considered a bug. If you don't like it, 
  562. you can live with the modeline problem.
  563. X.PP
  564. The same problem with the directory changing underneath you happens when
  565. X.I e
  566. inherits a .exrc for you (via "VIINHERIT") \- you get changed to that 
  567. directory while you are in vi.
  568. X.SH FILES
  569. X$HOME/.e \- the default e history file.
  570. X.SH "ENVIRONMENT VARIABLES"
  571. VIHIST \- The location used by e for the history.
  572. X.br
  573. VIPATH \- Search directories.
  574. X.br
  575. VIINHERIT \- If set,
  576. X.I e
  577. tries to inherit .exrc files.
  578. X.br
  579. VISAFEINHERIT \- Ensures you don't inadvertently go through someone
  580. else's .exrc file.
  581. X.SH BUGS
  582. The first character on a select line cannot be backspaced over.
  583. X.br
  584. The
  585. X.I vi
  586. option "\-" is not available. I should have chosen another letter.
  587. X.SH "SEE ALSO"
  588. ex(1), edit(1).
  589. X.SH AUTHOR
  590. Terry Jones
  591. X.br
  592. Department of Computer Science
  593. X.br
  594. University of Waterloo
  595. X
  596. X.\"
  597. X.\" Man page for e. Version 1.3
  598. X.\"
  599. X.\"    ------------------------------------------------------------------------
  600. X.\"    Terry Jones, Department Of Computer Science, University Of Waterloo
  601. X.\"         Waterloo Ontario Canada N2L 3G1
  602. X.\"
  603. X.\"    {ihnp4,allegra,decvax,utzoo,utcsri,clyde}!watmath!watdragon!tcjones
  604. X.\"    tcjones@dragon.waterloo.{cdn,edu} tcjones@WATER.bitnet
  605. X.\"    tcjones%watdragon@waterloo.csnet 
  606. X.\"    -------------------------------------------------------------------------
  607. X.\"
  608. END_OF_FILE
  609. if test 9576 -ne `wc -c <'e.1'`; then
  610.     echo shar: \"'e.1'\" unpacked with wrong size!
  611. fi
  612. chmod +x 'e.1'
  613. # end of 'e.1'
  614. fi
  615. if test -f 'e.c' -a "${1}" != "-c" ; then 
  616.   echo shar: Will not clobber existing file \"'e.c'\"
  617. else
  618. echo shar: Extracting \"'e.c'\" \(5750 characters\)
  619. sed "s/^X//" >'e.c' <<'END_OF_FILE'
  620. X#include "e.h"
  621. X
  622. void
  623. e(c, v)
  624. int c;
  625. char **v;
  626. X{
  627. X    /*
  628. X     * Process the command line. This gets a little messy as there are so
  629. X     * many ways e can be invoked. They are listed below and there is an
  630. X     * example provided in each of the switch cases to illustrate the 
  631. X     * particular one we are trying to handle.
  632. X     *
  633. X     * The idea in most cases is to get the arguments that will be passed
  634. X     * to vi into a character array (arg), and pass it to do_vi(). do_vi()
  635. X     * splits up the arguments and execs vi. Occasionally it is simpler and
  636. X     * do_vi() can be called more directly.
  637. X     *
  638. X     *
  639. X     * Command Line Options.
  640. X     * =====================
  641. X     *
  642. X     * No arguments.
  643. X     *
  644. X     *     (1) "e"
  645. X     *
  646. X     * One argument.
  647. X     *
  648. X     *     (2) "e -"
  649. X     *     (3) "e -#"                # is the number of some history item.
  650. X     *     (4) "e -r"
  651. X     *     (5) "e -pat"              pat is a search pattern.
  652. X     *     (6) "e +100"
  653. X     *     (7) "e ."
  654. X     *     (8) "e <filename > "
  655. X     *
  656. X     * Multiple arguments.
  657. X     *
  658. X     *     (9) "e fred harry joe"   Also handles "e -t tag", "e -r file" etc.
  659. X     *
  660. X     */
  661. X
  662. X
  663. X    switch (c){
  664. X        case 1: {
  665. X
  666. X            /* 
  667. X             * Command line option (1).
  668. X             * Example: "e"
  669. X             *
  670. X             * Just go and vi the last file that was e'ed.
  671. X             *
  672. X             */
  673. X
  674. X            check_hist();
  675. X            abandon();
  676. X            do_vi(hist[hist_count - 1]);
  677. X            break;
  678. X        }
  679. X        
  680. X        case 2:{
  681. X            switch ((*++v)[0]){
  682. X
  683. X                case '-':{
  684. X
  685. X                    if ((c = (*v)[1]) == '\0'){
  686. X
  687. X                        /* 
  688. X                         * Command line option (2).
  689. X                         * Example: "e -"
  690. X                         *
  691. X                         * This is a select from history, ask what they want.
  692. X                         *
  693. X                         */
  694. X
  695. X                        check_hist();
  696. X                        ask_hist();
  697. X                        do_vi(arg);
  698. X                    }
  699. X                    else if (isdigit(c)){
  700. X
  701. X                        /* 
  702. X                         * Command line option (3).
  703. X                         * Example: "e -3"
  704. X                         *
  705. X                         * Get the nth last file from the history and vi it.
  706. X                         *
  707. X                         */
  708. X
  709. X                        check_hist();
  710. X                        nth_hist(c-'0');
  711. X                        do_vi(arg);
  712. X                    }
  713. X                    else if (c == 'r' && (*v)[2] == '\0'){
  714. X
  715. X                        /* 
  716. X                         * Command line option (4).
  717. X                         * Example: "e -r"
  718. X                         *
  719. X                         * A recover, just pass it to vi and don't interfere.
  720. X                         *
  721. X                         */
  722. X
  723. X                        do_vi(*v);
  724. X                    }
  725. X                    else{
  726. X
  727. X                        /* 
  728. X                         * Command line option (5).
  729. X                         * Example: "e -pat"
  730. X                         *
  731. X                         * This is a pattern - try to match it.
  732. X                         *
  733. X                         */
  734. X
  735. X                        check_hist();
  736. X                        find_match(++*v);
  737. X                        do_vi(arg);
  738. X                    }
  739. X                    break;
  740. X                }
  741. X
  742. X                case '+':{
  743. X
  744. X                    /* 
  745. X                     * Command line option (6).
  746. X                     * Example: "e +100"
  747. X                     *
  748. X                     * A command, put it before the last file name.
  749. X                     *
  750. X                     */
  751. X
  752. X                    check_hist();
  753. X                    insert_cmd(*v);
  754. X                    do_vi(arg);
  755. X                    break;
  756. X                }
  757. X
  758. X                case '.':{
  759. X
  760. X                    /* 
  761. X                     * Command line option (7).
  762. X                     * Example: "e ."
  763. X                     * Example: "e .login"  (falls through to option (8)).
  764. X                     *
  765. X                     * Just give a history list if there is only a dot.
  766. X                     * Otherwise fall through as it must be a filename.
  767. X                     *
  768. X                     */
  769. X
  770. X                    if ((*v)[1] == '\0'){
  771. X                        register i;
  772. X
  773. X                        check_hist();
  774. X                        for (i = 0; i < hist_count; i++){
  775. X                            ok_fprintf(stderr, "\t[%d]: %s\n",
  776. X                                hist_count - i - 1, hist[i]);
  777. X                        }
  778. X                        abandon();
  779. X                    }
  780. X                    /* 
  781. X                     * The switch falls through in the case where there is a
  782. X                     * filename that starts with a period.
  783. X                     *
  784. X                     */
  785. X
  786. X                }
  787. X                /* FALLTHROUGH */
  788. X
  789. X                default :{
  790. X
  791. X                    /* 
  792. X                     * Command line option (8).
  793. X                     * Example: "e fred"
  794. X                     * Example: "e .login"  (fell through from option (8)).
  795. X                     *
  796. X                     * Looks like it's just a plain old file name. vi it!
  797. X                     *
  798. X                     */
  799. X
  800. X                    normal(*v);
  801. X                    do_vi(arg);
  802. X                    break;
  803. X                }
  804. X            }
  805. X            break;
  806. X        }
  807. X
  808. X        default:{
  809. X
  810. X            /* 
  811. X             * Command line option (9).
  812. X             * Example: "e fred harry joe"
  813. X             *
  814. X             * A bunch of arguments, fix the history & vi them all as normal.
  815. X             *
  816. X             */
  817. X
  818. X            multiple(c, v, ARG_CHARS);
  819. X            do_vi(arg);
  820. X            break;
  821. X        }
  822. X    }
  823. X}
  824. END_OF_FILE
  825. if test 5750 -ne `wc -c <'e.c'`; then
  826.     echo shar: \"'e.c'\" unpacked with wrong size!
  827. fi
  828. # end of 'e.c'
  829. fi
  830. if test -f 'read_hist.c' -a "${1}" != "-c" ; then 
  831.   echo shar: Will not clobber existing file \"'read_hist.c'\"
  832. else
  833. echo shar: Extracting \"'read_hist.c'\" \(6117 characters\)
  834. sed "s/^X//" >'read_hist.c' <<'END_OF_FILE'
  835. X#include "e.h"
  836. X
  837. X/*
  838. X * read_hist()
  839. X *
  840. X * Do some initialization type things such as finding out if the user has a
  841. X * uid, password entry, home directory etc. Then find out where the history
  842. X * is kept and check to see if it's there. If it's not just indicate this by
  843. X * returning -1 and let other functions deal with this problem as they see
  844. X * fit.
  845. X *
  846. X * If the history exists then read it. The format of the history file is
  847. X *
  848. X
  849. X/absolute/path/name/for/some/directory
  850. X\tfilename_1
  851. X\tfilename_2
  852. X\tfilename_3
  853. X\tfilename_4
  854. X/absolute/path/of/some/other/directory
  855. X\tsome_filename_or_other
  856. X\tanother_filename
  857. X
  858. X *
  859. X * Where \t is of course a single TAB.
  860. X * The files for a directory are kept in least recently used order. So in
  861. X * the above example, 'filename_1' was used before 'filename_2' and so on.
  862. X * There may be a maximum of HIST_LINES file names associated with each 
  863. X * directory.
  864. X *
  865. X * If the history is used and needs to be updated, then we will have to create
  866. X * a new file that looks pretty much like the current one. Unfortunately we
  867. X * will have to read and write the whole of the old file.
  868. X *
  869. X * Seeing as we are going to have to write the new history file, it doesn't
  870. X * make much sense to try and find the relevant directory in a clever manner
  871. X * (e.g. by keeping the history sorted by directory). The point is that
  872. X * we HAVE to read and write the whole file once so it doesn't really matter
  873. X * where we encounter the directory we want (if at all).
  874. X *
  875. X *
  876. X * We return the number of history items found after setting the pointers in
  877. X * hist[] to point to them. hist[0] points to the oldest filename, hist[1]
  878. X * to the next oldest etc etc... hist[hist_count - 1] to the most recently
  879. X * used.
  880. X *
  881. X */
  882. X
  883. int
  884. read_hist()
  885. X{
  886. X    static char line[MAXPATHLEN]; /* Static, as saved_line may point at it. */
  887. X    int h_index = 0;              /* # of history items found so far.       */
  888. X    register int cwd_len;         /* # of chars in the current dir name.    */
  889. X    struct stat sbuf;
  890. X
  891. X    cwd_len = strlen(cwd);
  892. X
  893. X    if (stat(ehist, &sbuf) == -1){
  894. X        return -1;
  895. X    }
  896. X
  897. X    emode = (int)sbuf.st_mode;
  898. X
  899. X    hist_fp = fopen(ehist, "r");
  900. X    if (!hist_fp){
  901. X        e_error("Could not open history '%s'.", ehist);
  902. X    }
  903. X
  904. X    /*
  905. X     * Open a new history file that will renamed to the old one once
  906. X     * we update. (If we update.)
  907. X     *
  908. X     */
  909. X
  910. X    get_temp();
  911. X
  912. X    /*
  913. X     * Make sure that the first line of the history starts with a '/'
  914. X     * This way we know we are not dealing with an old-style (pre version 1.3)
  915. X     * history file. The error message here is unsatisfactory - it should make
  916. X     * a better attempt to find out what's wrong and point them to the 
  917. X     * script for converting to the new format etc etc. Fortunately I'm the
  918. X     * only person in the world who uses e and so it's not a problem.
  919. X     *
  920. X     */
  921. X
  922. X    if (!fgets(line, MAXPATHLEN, hist_fp)){
  923. X        e_error("Could not read first line of '%s'.\n", ehist);
  924. X    }
  925. X
  926. X    if (line[0] != '/'){
  927. X        e_error("The history (%s) is munged. It is not in version %s format.",
  928. X            ehist, VERSION);
  929. X    }
  930. X
  931. X    ok_fprintf(tmp_fp, "%s", line);
  932. X
  933. X    /*
  934. X     * Get lines and write them to the new history until you see one that 
  935. X     * matches the directory we are in.
  936. X     *
  937. X     */
  938. X    while (fgets(line, MAXPATHLEN, hist_fp)){
  939. X
  940. X        register char *tmp = line;
  941. X        int room_left = HIST_LINES * MAXPATHLEN;
  942. X        char *room;
  943. X
  944. X        /* 
  945. X         * If it's not a path starting with a '/' then continue. 
  946. X         * We have a filename. Keep going until the next directory entry.
  947. X         *
  948. X         */
  949. X        if (line[0] != '/'){
  950. X            ok_fprintf(tmp_fp, "%s", line);
  951. X            continue;
  952. X        }
  953. X
  954. X        zap_nl(tmp);
  955. X
  956. X        /*
  957. X         * Test to see if this is the directory we want. tmp - line is the
  958. X         * length of the name of the found directory. Do a length test first
  959. X         * up to avoid a strcmp if possible.
  960. X         *
  961. X         */
  962. X        if (tmp - line != cwd_len || strcmp(line, cwd)){
  963. X            ok_fprintf(tmp_fp, "%s\n", line);
  964. X            continue;
  965. X        }
  966. X
  967. X        /* 
  968. X         * So we have found the directory we were looking for. Allocate a
  969. X         * hunk of space to read all the filenames. 
  970. X         */
  971. X        room = sbrk(room_left);
  972. X        if (room == (char *)-1){
  973. X            e_error("Could not sbrk().");
  974. X        }
  975. X
  976. X        /*
  977. X         * Read the filenames. If we reach a line that starts with a '/'
  978. X         * then we are onto the next directory in the history and we save
  979. X         * a pointer to this line to emit it later.
  980. X         *
  981. X         */
  982. X        while (fgets(room, room_left, hist_fp)){
  983. X            char *cp = hist[h_index] = room + 1;
  984. X            zap_nl(cp);
  985. X            room_left -= (cp - room);
  986. X
  987. X            /*
  988. X             * In theory we should never run out of space, but in case we do
  989. X             * we might as well try to grab some more rather than just dying.
  990. X             *
  991. X             */
  992. X            if (room_left <= MAXPATHLEN){
  993. X                room_left = HIST_LINES * MAXPATHLEN;
  994. X                room = sbrk(room_left);
  995. X                if (room == (char *)-1){
  996. X                    e_error("Could not sbrk().");
  997. X                }
  998. X            }
  999. X            
  1000. X            if (*room == '/'){
  1001. X                saved_line = room; /* Read one too many! */
  1002. X                return h_index;
  1003. X            }
  1004. X
  1005. X            room = cp + 1;
  1006. X            h_index++;
  1007. X
  1008. X            /*
  1009. X             * Check to see if we have read HIST_LINES filenames. If we have,
  1010. X             * make sure that the next line is in fact a directory (by
  1011. X             * verifying that it starts with a '/'.
  1012. X             *
  1013. X             */
  1014. X            if (h_index == HIST_LINES){
  1015. X                if (fgets(line, MAXPATHLEN, hist_fp)){
  1016. X                    if (line[0] != '/'){
  1017. X                        e_error("History contains too many entries!");
  1018. X                    }
  1019. X                    else{
  1020. X                        tmp = line;
  1021. X                        zap_nl(tmp);
  1022. X                        saved_line = line;
  1023. X                    }
  1024. X                }
  1025. X                return HIST_LINES;
  1026. X            }
  1027. X        }
  1028. X        return h_index;
  1029. X    }
  1030. X    return h_index;
  1031. X}
  1032. END_OF_FILE
  1033. if test 6117 -ne `wc -c <'read_hist.c'`; then
  1034.     echo shar: \"'read_hist.c'\" unpacked with wrong size!
  1035. fi
  1036. # end of 'read_hist.c'
  1037. fi
  1038. echo shar: End of archive 3 \(of 3\).
  1039. cp /dev/null ark3isdone
  1040. MISSING=""
  1041. for I in 1 2 3 ; do
  1042.     if test ! -f ark${I}isdone ; then
  1043.     MISSING="${MISSING} ${I}"
  1044.     fi
  1045. done
  1046. if test "${MISSING}" = "" ; then
  1047.     echo You have unpacked all 3 archives.
  1048.     rm -f ark[1-9]isdone
  1049. else
  1050.     echo You still need to unpack the following archives:
  1051.     echo "        " ${MISSING}
  1052. fi
  1053. ##  End of shell archive.
  1054. exit 0
  1055.  
  1056.